/**
 **************************************************************************************************************************
 * Base class for all components so that they can be in an entity
 * Components should not have behaviours, but rather contain data accessed by processors
 * This is why there is no pure virtual update
 **************************************************************************************************************************
 * @file RBComponent.h
 **************************************************************************************************************************/

#pragma once

#ifdef  HEADER_MSG
#pragma HEADER_MSG(RBComponent.h)
#endif


/**************************************************************************************************************************
 * Includes
 **************************************************************************************************************************/

#define RB_DECLARE_COMPONENT(CLASSNAME) \
    static uint16 ms_uiComponentIdx;    \
    static uint16 GetClassIdx() { return ms_uiComponentIdx;}

#define RB_IMPLEMENT_COMPONENT(CLASSNAME) \
    uint16 CLASSNAME::ms_uiComponentIdx = 0xFFFF; \
    CLASSNAME* RBTComponent<CLASSNAME>::Instances = NULL;
    
namespace RBComponent
{
    extern uint16 g_componentCount;
    template<class TComponent> void RegisterComponent()
    {
        TComponent::Init(&g_componentCount);
    }

    template<class TComponent> void UnregisterComponent()
    {
        TComponent::Release();
    }

}

#include "RBHandle.h"
#include "stb.h"

/**************************************************************************************************************************
 * Forward declarations
 **************************************************************************************************************************/
RBDeclareHandle(RBEntity);
class RBStream;
class RBTransform;

/**************************************************************************************************************************
 * Classes
 **************************************************************************************************************************/

template<class TComponent>
class RBTComponent
{
public:
    typedef RBHandle<TComponent> RBTComponentHandle;

    static void                     Create      (RBEntityHandle entityHandle, RBTComponentHandle* pHandles, uint32 count);
    static RBTComponentHandle       Create      (RBEntityHandle entityHandle);

    static TComponent&              Get         (RBTComponentHandle handle);
    static void                     Destroy     (RBTComponentHandle handle);

    RBEntityHandle GetEntityHandle() const { return m_entity; }

    static void                     Init        (uint16* componentCount);
    static void                     Release     ();

protected:
    RBTComponent(RBEntityHandle entityHandle) : m_entity(entityHandle) {}

    RBEntityHandle m_entity;
    static TComponent* Instances;

};

template<class TComponent>
void RBTComponent<TComponent>::Init(uint16* componentCount)
{
    TComponent::ms_uiComponentIdx = *componentCount;
    (*componentCount)++;
}


template<class TComponent>
void RBTComponent<TComponent>::Release()
{
    stb_arr_free(TComponent::Instances);
}


template<class TComponent>
RBHandle<TComponent> RBTComponent<TComponent>::Create( RBEntityHandle entityHandle )
{
    RBTComponentHandle cmpHandle;
    Create(entityHandle, &cmpHandle, 1);
    return cmpHandle;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<class TComponent>
void RBTComponent<TComponent>::Create( RBEntityHandle entityHandle, RBHandle<TComponent>* pHandles, uint32 count )
{
    for (uint32 ui=0; ui < count; ++ui)
    {
        pHandles[ui] = (RBTComponentHandle)stb_arr_len(Instances);
        stb_arr_push_obj(Instances, TComponent(entityHandle));
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<class TComponent>
TComponent& RBTComponent<TComponent>::Get( RBTComponentHandle handle )
{
    return Instances[handle];
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<class TComponent>
void RBTComponent<TComponent>::Destroy( RBTComponentHandle /*handle*/ )
{

}
